Some scala basics

A few very simple characteristics of the Scala language. No Spark specifics yet.

Mostly taken from A short primer on Scala. See also additional documentation in Scala overviews and the Scala cheatsheet

In terms of general syntax, Scala is quite similar to Java. One difference is that it is less picky with semicolons: they are optional at the end of the line.

Variables

Mutable and immutable values. Type inference


In [6]:
// A mutable variable, defined with explicit type specification
var a: Int = 5
a = a + 1
println(a)

// Inmutable variables
val v1: Double = 6.2
val v2: String = "Hi!"
println( v1, v2)

// Same as before, but now we use type inference
val v1 = 6.2
val v2 = "Hi!"
println( v1, v2)
println( v1.getClass, v2.getClass )


6
(6.2,Hi!)
(6.2,Hi!)
(double,class java.lang.String)

Functions


In [6]:
/* Define a function. This one is a one-liner, otherwise we would use braces */
def fact(n: Int): Int =  if (n == 0) 1 else n*fact(n-1)

In [7]:
// Use the function
fact(10)


Out[7]:
3628800

Anonymous functions

Functions can also be defined on the fly. Anonymous functions can be assigned to a variable so that we can call it later


In [2]:
// A function, with type specification
// (if the context was clear, we could use type inference)
val cube = (x : Int)  => x*x*x

cube(7)


Out[2]:
343

In [4]:
// Same thing, but using explicit return type specification
val cube: Int => Double = x => x*x*x

cube(5)


Out[4]:
125.0

In [9]:
// If the function is more complex, we use a brace block
val cubeOrSquare = (x: Int) => { if( x < 10 )
                                    x*x*x
                                 else
                                    x*x }
                                    
print( cubeOrSquare(7), cubeOrSquare(11) )


(343,121)

There is also a shorthand used in which we use the underscore (_) as a placeholder for anonymous arguments, and we skip the argument list. See below

Higher order functions

These are functions that take another function as a paramete and/or return a function


In [5]:
// A function that takes another function and a value, and applies the function to the square of the value 
def applySquared( func: Int => Int, value: Int) = func( value*value )

// Prepare the function we will pass
val minusOne = (x : Int) => x - 1

// This should compute x^2 - 1
print( applySquared( minusOne, 3 ) )

// We can also pass directly an anonymous function. This is x^2 + 2
applySquared( _ + 2, 6 )


8
Out[5]:
38

Classes


In [3]:
/* Define a class */
class Point( xc: Int, yc: Int ) {
    var x: Int = xc
    var y: Int = yc
    def move(dx: Int, dy: Int) {
        x = x + dx
        y = y + dy
    }
    override def toString(): String = "(" + x + ", " + y + ")";
}

/* Create an instance, and operate with it */
val p = new Point( 10, 11 )
p.move( 2, -1 )
println( p )


(12, 10)

Collections

See Scala collections for documentation.


In [11]:
var l = List( 1, 2, 3, 4, 5 )

In [12]:
l.reverse


Out[12]:
List(5, 4, 3, 2, 1)

In [13]:
var s = Set( "a", "b", "c", "d")

In [14]:
s.contains( "c" )


Out[14]:
true

In [15]:
s & Set("a","c","f")


Out[15]:
Set(a, c)

Ranges

Ranges are collections of numerical elements


In [25]:
val r = Range(1,10)

r


Out[25]:
Range(1, 2, 3, 4, 5, 6, 7, 8, 9)

There is also a special syntax to define ranges using to or until


In [27]:
1 to 10


Out[27]:
Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

In [32]:
// define a range with a fractional increment, and convert the result to Array
(1.0 until 10.0 by 0.5).toArray


Out[32]:
Array(1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5, 8.0, 8.5, 9.0, 9.5)

Operations on collections

Scala collection classes define abstract methods that apply to their contents.

For instance, the map function is a higher order function, which takes a function as an argument and applies them to all elements in the collection:


In [12]:
val numbers = List(1,2,3,4)

// We use here an anonymous function
numbers.map( x => 2 * x )


Out[12]:
List(2, 4, 6, 8)

In [13]:
// Same, but now with the shorthand using the underscore, which is interpreted as a reference to an anonymous argument
numbers.map( 2 * _ )


Out[13]:
List(2, 4, 6, 8)

In [16]:
// Another example
numbers.filter( _ <= 2 )


Out[16]:
List(1, 2)

Another variant: the reduceLeft function applies a binary operation (two parameters) successively, until all elements in the collection have been consumed:


In [16]:
numbers.reduceLeft( (a, b) => a + b )


Out[16]:
10

In [17]:
// Again, using the underscore shorthand (each underscore refers to one of the two parameters)
numbers.reduceLeft( _ + _ )


Out[17]:
10